#ifndef __FINITE_STATE_MACHINE_H__
#define __FINITE_STATE_MACHINE_H__

#include "common.h"
#include <set>
#include <map>
#include <iterator>
#include <stdarg.h>

BEG_DEF_NAMESPACE_FSM

#define OK			0 /* ok */
#define ERR			1 /* general error,mostly to be used for checking the return value */
#define ERR_STATE_DUPLICATE	2 /* already exist the same state code */
#define ERR_STATE_NOTEXIST 	3 /* the specific state code don't exist*/
#define ERR_STATE_INVALID	4 /* the mCurrStateCode is invalid */
#define ERR_NOT_SUB_STATE	5
#define ERR_STATE_ENTRY		6 /**/
#define ERR_STATE_LEAVE		7 /**/

typedef int FSM_STATE_CODE ;
#define BEFORE_BEGIN -1
#define AFTER_END -2
#define ISVALIDSTATE( STATE )	(STATE > BEFORE_BEGIN)


template <typename T> class FiniteStateMachine;
template <typename T> class FSMState {
	typedef std::set< FSM_STATE_CODE > FSM_STATE_CODE_SET;
public:
	FSMState();
	virtual ~FSMState();
	/** 
	 * @brief assemble the current state with the parameters
	 * 
	 * @param stateCode 	the state code of current state
	 * @param action	the action of currenassemblet state
	 * @param ...		the substate code of current state
	 * 
	 * @return 
	 */
	int BuildState( FSM_STATE_CODE stateCode , ... );
private:
	bool IsSubStateCode( FSM_STATE_CODE stateCode );
	virtual bool HandleEntry( T pUserData , const void * pInputData ){ 
		pUserData=pUserData ; 
		pInputData=pInputData; 
		return true;
	}
	virtual bool HandleLeave( T pUserData , const void * pInputData ){
		pUserData=pUserData ; 
		pInputData=pInputData; 
		return true;
	}
	virtual FSM_STATE_CODE HandleAction(T pUserData , const void * pInputData )=0;
private:
	FSM_STATE_CODE mStateCode;
	FSM_STATE_CODE_SET mSubStateCodeSet;
private:
	friend class FiniteStateMachine<T>;
};

template <typename T>
FSMState<T>::FSMState(){
	mStateCode = BEFORE_BEGIN;
}

template <typename T>
FSMState<T>::~FSMState(){
}

template <typename T>
int FSMState<T>::BuildState( FSM_STATE_CODE  stateCode , ... ){
	mStateCode = stateCode;

	va_list args;
	va_start(args, stateCode);
	while (1){
		FSM_STATE_CODE sCode = va_arg( args, FSM_STATE_CODE );
		if( sCode <= BEFORE_BEGIN ){
			break;
		}
		mSubStateCodeSet.insert( sCode );
	}
	va_end(args);
	return 0;
}

template <typename T>
bool FSMState<T>::IsSubStateCode( FSM_STATE_CODE stateCode ){
	return (mSubStateCodeSet.find(stateCode) != mSubStateCodeSet.end());
}

/*************** Defination of FiniteStateMachine **********/

template< typename T>
class FiniteStateMachine{
	typedef std::map< FSM_STATE_CODE , FSMState<T> * > FSM_STATE_MAP;
public:
	FiniteStateMachine();
	int Trigger( T userData , const void * pData );
	int BuildFSM(FSM_STATE_CODE beginStateCode , FSM_STATE_CODE endStateCode , ... );

private:
	int	CheckState( FSM_STATE_CODE stateCode , FSMState<T> ** ppState);
	FSMState<T> * FindState( FSM_STATE_CODE stateCode );
private:
	FSM_STATE_CODE mCurrStateCode;
	FSM_STATE_CODE mBeginStateCode;
	FSM_STATE_CODE mEndStateCode;

	FSM_STATE_MAP  mStateMap;

	FSMState<T> * mpPreviousState;
	FSMState<T> * mpCurrentState;

};

#define CreateFSMState( TYPE , VARIABLE , STATECODE , ... ) \
	 TYPE *VARIABLE = new TYPE();VARIABLE->BuildState( STATECODE ,__VA_ARGS__)

template <typename T>
FiniteStateMachine<T>::FiniteStateMachine(){
	mCurrStateCode	= BEFORE_BEGIN;
	mBeginStateCode	= BEFORE_BEGIN;
	mEndStateCode	= AFTER_END;
	mpPreviousState = NULL;
	mpCurrentState = NULL;
}

template <typename T>
FSMState<T> * FiniteStateMachine<T>::FindState( FSM_STATE_CODE stateCode ){
	typename FSM_STATE_MAP::iterator iter = mStateMap.find( stateCode );
	iter = mStateMap.find( stateCode );
	if( iter == mStateMap.end() ){
		return NULL;
	}
	return iter->second;
}

template <typename T>
int FiniteStateMachine<T>::CheckState( FSM_STATE_CODE stateCode , FSMState<T> ** ppState ){
	/* check if the state code is valid*/
	if( !ISVALIDSTATE( stateCode ) ){
		return ERR_STATE_INVALID;
	}

	/* check if the stateCode is exist */
	FSMState<T> * ptmpState = NULL;
	if( ( ptmpState = FindState(stateCode)) == NULL  ){
		return ERR_STATE_NOTEXIST; 
	}
	if( ppState ){
		*ppState = ptmpState;
	}
	return OK;
}


template <typename T>
int FiniteStateMachine<T>::BuildFSM(	FSM_STATE_CODE beginStateCode , 
				   	FSM_STATE_CODE endStateCode , ... ){


	va_list args;
	int retVal = OK ;

	FSM_STATE_CODE tmpStateCode;
	FSMState<T> * ptmpState;

	va_start(args, endStateCode);
	while (1){
		ptmpState = va_arg( args, FSMState<T>* );
		if( ptmpState == NULL){
			break;
		}
		tmpStateCode = ptmpState->mStateCode;

		/* there must be unique object per state code in the state code map */
		if( (retVal = CheckState( tmpStateCode, NULL)) != ERR_STATE_NOTEXIST ){
			return  retVal == OK?ERR_STATE_DUPLICATE:retVal;
		}

		mStateMap.insert( std::make_pair(tmpStateCode , ptmpState) );
		if( tmpStateCode == endStateCode ){
			break;
		}
	}
	va_end(args);

	/* check the start state */
	if( (retVal=CheckState( beginStateCode , &mpCurrentState)) != OK ){
		return retVal;
	}
	mBeginStateCode = beginStateCode;
	mCurrStateCode = beginStateCode;

	mpPreviousState = NULL;

	/* check the end state */
	if( (retVal = CheckState( endStateCode , NULL)) != OK ){
		return retVal;
	}
	mEndStateCode = endStateCode ;

	return OK;
}

template <typename T>
int FiniteStateMachine<T>::Trigger( T userData , const void * pData ){
	int retVal;
	FSM_STATE_CODE tmpStateCode = BEFORE_BEGIN;
	if( mpPreviousState ){
		if(!mpPreviousState->HandleLeave( userData , pData )){
			return ERR_STATE_ENTRY;
		}
	}

	if( NULL == mpCurrentState ){
		if( (retVal = CheckState( mCurrStateCode , &mpCurrentState )) != OK ){
			return retVal;
		}
	}

	/*check if the returned state code is the sub state of current state */
	tmpStateCode = mpCurrentState->HandleAction(userData , pData );
	if( mpCurrentState->IsSubStateCode(tmpStateCode) ){
		mCurrStateCode = tmpStateCode ;
	}else{
		return ERR_NOT_SUB_STATE;
	}

	mpPreviousState = mpCurrentState;

	if( (retVal = CheckState( mCurrStateCode , &mpCurrentState )) != OK ){
		return retVal;
	}
	
	return (mpCurrentState->HandleEntry( userData , pData )?OK:ERR_STATE_LEAVE) ;
}

END_DEF_NAMESPACE_FSM

#endif
